package com.runda.partypolicy.app.others.Rxjava;

import android.text.TextUtils;


import com.runda.partypolicy.app.others.Constants;
import com.runda.partypolicy.app.repository.RepositoryException;
import com.runda.partypolicy.app.repository.RepositoryResult;
import com.runda.partypolicy.app.repository.live.LiveDataWrapper;

import org.reactivestreams.Publisher;

import java.util.concurrent.TimeUnit;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;


/**
 * author: RD_CY
 * date: 2016/11/3
 * version: 1.0
 * description:RxJava处理工具
 */

public class RxUtil {

    /**
     * 统一点击事件抖动和延时处理操作
     */
    public static <T> ObservableTransformer<T, T> operateDelay() {
        return upstream -> upstream
                .delay(Constants.TIME_DELAY_CLICK, TimeUnit.MILLISECONDS)
                .throttleFirst(Constants.TIME_THROTTLE_CLICK, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 统一点击事件抖动和延时处理操作
     */
    public static <T> FlowableTransformer<T, T> operateDelayBP() {
        return upstream -> upstream
                .delay(Constants.TIME_DELAY_CLICK, TimeUnit.MILLISECONDS)
                .throttleFirst(Constants.TIME_THROTTLE_CLICK, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 统一线程处理
     */
    public static <T> ObservableTransformer<T, T> rxSchedulerHelper() {
        return upstream -> upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 统一线程处理
     */
    public static <T> FlowableTransformer<T, T> rxSchedulerHelperBP() {
        return upstream -> upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 统一返回结果处理
     */
    public static <T> ObservableTransformer<RepositoryResult<T>, T> handleResult() {
        return new ObservableTransformer<RepositoryResult<T>, T>() {
            @Override
            public ObservableSource<T> apply(Observable<RepositoryResult<T>> upstream) {
                return upstream
                        .flatMap((Function<RepositoryResult<T>, ObservableSource<T>>) new Function<RepositoryResult<T>, ObservableSource<T>>() {
                            @Override
                            public ObservableSource<T> apply(RepositoryResult<T> tRepositoryResult) throws Exception {
                                if ("200".equals(tRepositoryResult.getStatusCode())) {
                                    return createData(tRepositoryResult.getData());
                                } else if ("404".equals(tRepositoryResult.getStatusCode())) {
                                    return Observable.error(new RepositoryException(Constants.ERROR_CODE_REMOTE,
                                            TextUtils.isEmpty(tRepositoryResult.getMessage()) ?
                                                    Constants.ERROR_STRING_CONNECT : tRepositoryResult.getMessage()));
                                } else if ("202".equals(tRepositoryResult.getStatusCode())) {
                                    return Observable.error(new RepositoryException(Constants.ERROR_CODE_TOKENVOERTIME,
                                            TextUtils.isEmpty(tRepositoryResult.getMessage()) ?
                                                    Constants.ERROR_STRING_TOKENVOERTIME : tRepositoryResult.getMessage()));
                                } else {
                                    return Observable.error(new RepositoryException(Integer.parseInt(tRepositoryResult.getStatusCode()),
                                            TextUtils.isEmpty(tRepositoryResult.getMessage()) ?
                                                    Constants.ERROR_STRING_SERVICE : tRepositoryResult.getMessage()));
                                }
                            }
                        });
            }
        };
    }

    /**
     * 统一返回结果处理
     */
    public static <T> FlowableTransformer<RepositoryResult<T>, LiveDataWrapper<T>> handleResultBP() {
        return new FlowableTransformer<RepositoryResult<T>, LiveDataWrapper<T>>() {
            @Override
            public Publisher<LiveDataWrapper<T>> apply(Flowable<RepositoryResult<T>> upstream) {
                return upstream
                        .flatMap((Function<RepositoryResult<T>, Publisher<LiveDataWrapper<T>>>) new Function<RepositoryResult<T>, Publisher<LiveDataWrapper<T>>>() {
                            @Override
                            public Publisher<LiveDataWrapper<T>> apply(RepositoryResult<T> tRepositoryResult) throws Exception {
                                if ("200".equals(tRepositoryResult.getStatusCode())) {
                                    return createDataBP(tRepositoryResult.getData());
                                } else if ("404".equals(tRepositoryResult.getStatusCode())) {
                                    return Flowable.error(new RepositoryException(Constants.ERROR_CODE_REMOTE,
                                            TextUtils.isEmpty(tRepositoryResult.getMessage()) ?
                                                    Constants.ERROR_STRING_CONNECT : tRepositoryResult.getMessage()));
                                } else if ("202".equals(tRepositoryResult.getStatusCode())) {
                                    return Flowable.error(new RepositoryException(Constants.ERROR_CODE_TOKENVOERTIME,
                                            TextUtils.isEmpty(tRepositoryResult.getMessage()) ?
                                                    Constants.ERROR_STRING_TOKENVOERTIME : tRepositoryResult.getMessage()));
                                } else if ("401".equals(tRepositoryResult.getStatusCode())) {
                                    return Flowable.error(new RepositoryException(Constants.ERROR_CODE_TOKENVOERTIME,
                                            TextUtils.isEmpty(tRepositoryResult.getMessage()) ?
                                                    Constants.ERROR_STRING_TOKENVOERTIME : tRepositoryResult.getMessage()));
                                } else {
                                    return Flowable.error(new RepositoryException(Integer.parseInt(tRepositoryResult.getStatusCode()),
                                            TextUtils.isEmpty(tRepositoryResult.getMessage()) ?
                                                    Constants.ERROR_STRING_SERVICE : tRepositoryResult.getMessage()));
                                }
                            }
                        });
            }
        };
    }

    /**
     * 生成Observable
     */
    public static <T> Observable<T> createData(final T t) {
        return Observable.create(emitter -> {
            try {
                emitter.onNext(t);
                emitter.onComplete();
            } catch (Exception e) {
                emitter.onError(e);
            }
        });
    }

    /**
     * 生成Flowable
     */
    public static <T> Flowable<LiveDataWrapper<T>> createDataBP(final T t) {
        return Flowable.create(subscriber -> {
            try {
                //转化为LiveDataWrapper
                subscriber.onNext(new LiveDataWrapper<T>(true, t));
                subscriber.onComplete();
            } catch (Exception e) {
                subscriber.onError(e);
            }
        }, BackpressureStrategy.LATEST);
    }
}
